package org.codesketch.flamingo

import org.codesketch.flamingo.domain.Response;
import org.codesketch.flamingo.utils.JSONUtils;

import grails.converters.JSON

class NodeController {
	
	NodeService nodeService
	static Monitor monitor
	
	def scaffold = Node
	
	/*
	 * Redirects all the default call to all
	 */
	def index = {
		redirect(action: "list", params: params)
	}
	
	/**
	 * Retrieve a list of all the configured node that matches the given request.
	 * @return the list of configured node
	 */
	def list() {
		// Sets the maximum number of returned node
		params.max = Math.min(params.max ? params.int('max') : 10, 100);
//		def res = Node.list(params)
		render Node.list(params) as JSON
//		render JSONUtils.toJSON(Node.list(params));
	}
	
	/**
	 * Toggle Varnish monitoring service.
	 * @return the current monitoring status
	 */
	def monitor() {
		if(null == monitor) {
			monitor = new Monitor()
		}
		if(!monitor.isRunning()) {
			new Thread(monitor).start()
			render "STARTED";
		} else {
			monitor.stop()
			render "STOPPED"
		}
	}
	
//	def age() {
//		render nodeService.age();
//	}
	
	def configuration() {
		Response<String> resp = new Response<String>();
		try {
			def conf = nodeService.configuration()
			resp.setStatus(200);
			resp.setMessage("OK");
			resp.setData(conf);
		} catch (Exception e) {
			resp.setStatus(500);
			resp.setMessage(e.getMessage());
			resp.setData(null);
		}
		render resp as JSON
	}
	
	/* 
	 * #################################
	 * Varnish administration end-points
	 * #################################
	 */
	/**
	 * List the available VCL for the requested node.
	 * @return a list of the VCL available on the requested node as a JSON format
	 */
	def ls() {
		def vcl = nodeService.ls(params.id.toLong());
		render vcl as JSON
	}
	/**
	 * Load an compile the given VCL to the requested node. The VCL will be named using the 
	 * provided name.
	 * @return the VCL loading and compilation outcome 
	 */
	def inline() {
		def vcl = nodeService.inline(params.id.toLong(), params.name, params.vcl);
		render vcl as JSON
	}
	/**
	 * Discard the requested VCL from the requested node.
	 * @return the VCL discard result
	 */
	def discard() {
		def vcl = nodeService.discard(params.id.toLong(), params.name);
		render vcl as JSON
	}
	/**
	 * Use the requested VCL on the requested node. 
	 * @return the VCL use outcome.
	 */
	def use() {
		def vcl = nodeService.use(params.id.toLong(), params.name);
		render vcl as JSON
	}
	/**
	 * Show the requested VCL on the requested node
	 * @return the show outcome
	 */
	def show() {
		def vcl = nodeService.show(params.id.toLong(), params.name);
		render vcl as JSON
	}
	/**
	 * Set the requested parameter on the requested node
	 * @return
	 */
	def pset() {
		def resp = nodeService.pset(params.id.toLong(), params.name, params.value);
		render resp as JSON
	}
	/**
	 * Show the requested parameter for the requested node
	 * @return
	 */
	def pshow() {
		def resp = nodeService.pshow(params.id.toLong(), params.arg);
		render resp as JSON
	}
	/**
	 * Invalidate contents on the requested node using the provided expression.
	 * @return
	 */
	def ban() {
		def vcl = nodeService.ban(params.id.toLong(), params.exp);
		render vcl as JSON
	}
	/**
	 * Displays the ban list fro the requested node.
	 * @return
	 */
	def blist() {
		def resp = nodeService.blist(params.id.toLong());
		render resp as JSON
	}
	/**
	 * Ban all the contents on teh requested node whose URL matches the given regular expression.
	 * @return
	 */
	def burl() {
		def resp = nodeService.burl(params.id.toLong(), params.exp);
		render resp as JSON
	}
	
	// -- Helper
	
	/**
	 * Internal class perform the node monitoring as a separate thread.
	 * @author quirino
	 *
	 */
	private class Monitor implements Runnable {
		private static final SLEEP_TIME_MS = 30000;
		private boolean stop
		private boolean running
				
		Monitor() {
			stop = false
			running = false
		}
		
		@Override
		void run() {
			running = true
			while(!stop) {
				nodeService.monitor()
				System.out.println("Monitor: " + new Date().toString());
				try {
					Thread.sleep(SLEEP_TIME_MS);
				} catch(InterruptedException e) {
					if(stop) {
						break;
					}
				}
			}
			running = false
		}
		/**
		 * Stops the monitoring service.
		 */
		void stop() { stop = true }
		/**
		 * Check if the monitoring service is running.
		 * @return true if monitoring service is running, false otherwise.
		 */
		boolean isRunning() { return running }
	}
}
